Entity Definition in NoLang
Each NoLang app contains at least one entity. They are defined in JSON schema format. Nolang adds some keywords to standard JSON schemas to define schema of entities. An entity schema can be defined as follows:
{
//(string) Identifier of this entity
$id : "entity1" ,
//(object) List of fields in this entity
properties : {} ,
//(object) Storage specification of this entity
$$storage : ... ,
//(array) Array of rules for validation or other type of rules
$$rules : [] ,
//(array) Array of access of roles to this entity
$$roles : [] ,
//(array) List of methods in this entity
$$methods : [] ,
//(array) Array of ids of used entities
$$uses : ["entity2","entity3"] ,
}
$id
is the identifier of this entity. It must be unique in the app. It is better to don't use dot in ids.properties
shows list of fields in this entity. Each field has a title, type and more attributes.{
"$id": "products",
"title": "products",
"properties": {
"productKey": {
"title": "Product Key",
"type": "number"
},
"productName": {
"title": "Name of product",
"type": "string",
"minLength": 3
},
"address": {
"title": "Address of manufacture",
"type": "object",
"$ref": "address"
},
"stores": {
"title": "Stores",
"description": "List of stores sell this product",
"type": "array",
"items": {
"type": "number",
"$$rel": {
"schema": "store"
}
}
}
}
}
For each entity we can set its specific
$$storage
configuration. otherwise NoLang uses the default storage
in the app config file. For more information see the Storage section.In addition to checking the type of each field in the properties keyword, NoLang includes another feature to check more complicated states. By using
In the below sample, there is an entity with two fields named "status" and "progress". The "progress" is a number between 0 and 10. There are, however, some rules: if "progress" is 0, "status" must be "Not Started" and vice versa. If the "progress" is 10, then the "status" must be "Done". There is another rule with
$$rules
, some rules of relationship between fields of an entity can be defined in JSON Logic format. It can also be defined some triggering rules. In the below sample, there is an entity with two fields named "status" and "progress". The "progress" is a number between 0 and 10. There are, however, some rules: if "progress" is 0, "status" must be "Not Started" and vice versa. If the "progress" is 10, then the "status" must be "Done". There is another rule with
ruleId
"triggerRule1" and with ruleType
"trigger". It must be run in "afterCreate" rule time. ruleTime
can has one value of "beforeCreate", "afterCreate", "beforeUpdate", "afterUpdate", "beforeDelete", "afterDelete", "onSearch", "onRead", "onWiew", "onLoad", "onStorageConnected" and "every". if ruleTime
was equal to "every", we must set schedule
like a crontab. Finally, we have the ruleDef
, a NoLang script which runs at trigger time.{
//(string) key of this rule
ruleId : "check1" ,
//(array) which schemas are related to this rule, items are addresses of related INNER nodes
schemas : ['schema1', 'schema2'] ,
//(string) title of rule for advisor
title : "check value" ,
//(string) on [action] [error] [if] do
description : "a description about this rule" ,
//(one or array of CRUD actions) this rule will be triggered before Delete for example
before : "D" ,
//(one action or array of actions) this rule will be triggered after Create or Update for example
after : ["C","U"] ,
//(string) cron expression for trigger this rule
schedule : "0 30 10 * * *" ,
//(string) timezone of the schedule
timezone : "Asia/Tehran" ,
//(string,array) error code(s) which will trigger this rule
error : 'ERR2' ,
//(object) jsonlogic or object of condition,
//after any trigger this condition will be checked and it is not a trigger itself.
condition : {
">": [
{
"var": "field1"
},
1
]
} ,
//(object) jsonlogic or object of condition, for any CRUD action this check must be returns true
check : {
"!=": [
{
"var": "data.field1"
},
"0"
]
} ,
//(object) object to be assigned to the object this is created or updated
set : {
"field3": {
"+": [
"{{data.field1}}",
"{{data.field2}}"
]
},
"field4": "{{ Date.now()}}"
} ,
//(object) on triggering this rule this scripts will be ran
script : {
"$schema": "schemaX",
"$header": {
"action": "D",
"filter": {
"field2": "{{data.field2}}"
}
}
} ,
//(object) an object or jsonLogic to filter data list after retrieve data
filter : {
"schoolId": "{{user.schoolId}}"
} ,
//(boolean) run async this rule, default is false
async : true ,
//(string) message if check failed
message : "A message from server" ,
}
There are a number of access rights associated with an entity, represented by
$$roles
. A schema without $$roles has no restrictions. access
is equal to a set of first letters of Create, Read, Update, Delete or All.{
"$$roles": [
{
"roleId": "*",
"permissions": [
{
"access": [
"R"
]
}
]
},
{
"roleId": "supervisor",
"permissions": [
{
"access": [
"R",
"U"
]
}
]
},
{
"roleId": "admin",
"permissions": [
{
"access": [
"A"
]
}
]
}
]
}
It is possible to have some methods in an entity. Using
$$methods
we can define methods for entities.{
"$id": "entity-with-methods",
"properties": {},
"$methods": [
{
"name": "sendText",
"params": {
"mobileNo": {
"type": "string"
},
"text": {
"type": "string"
}
},
"handler": [
{
"$$schema": "sms_queue",
"$$header": {
"action": "C"
},
"receiver": "{{params.mobileNo}}",
"text": "{{params.text}}"
}
]
},
{
"name": "wait",
"params": {
"seconds": {
"type": "number"
}
},
"jsHandler": "../methods/myMethods.js"
}
]
}
In the above schema there are two methods. By calling first method it would create an element in the "sms_queue" entity. Next method has a javascript handler. Invoking it would cause an wait. The javascript handler file myMethods.js is like bellow:
module.exports = {
wait : async function () {
await new Promise(resolve => {
setTimeout(resolve, this.params.seconds*1000)
})
return {success: true, message: 'waited for '+this.params.seconds+' seconds'}
}
}
For calling methods we must run a NoLang Script with action M.